package com.alibaba.csp.sentinel.dashboard.service;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.*;
import com.alibaba.csp.sentinel.dashboard.discovery.AppInfo;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.repository.gateway.InMemApiDefinitionStore;
import com.alibaba.csp.sentinel.dashboard.repository.gateway.InMemGatewayFlowRuleStore;
import com.alibaba.csp.sentinel.dashboard.repository.rule.*;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author: shaozeming
 * @date: 2022/8/8 20:15
 * @description: 规则初始化
 **/
@Service
public class InitService implements SmartInitializingSingleton {

    @Autowired
    @Lazy
    private AppManagement appManagement;

    @Resource
    protected DynamicRuleProvider<List<RuleEntity>> ruleProvider;

    @Autowired
    private InMemAuthorityRuleStore inMemAuthorityRuleStore;

    @Autowired
    private InMemDegradeRuleStore inMemDegradeRuleStore;

    @Autowired
    private InMemFlowRuleStore inMemFlowRuleStore;

    @Autowired
    private InMemParamFlowRuleStore inMemParamFlowRuleStore;

    @Autowired
    private InMemSystemRuleStore inMemSystemRuleStore;

    @Autowired
    private InMemGatewayFlowRuleStore inMemGatewayFlowRuleStore;

    @Autowired
    private InMemApiDefinitionStore inMemApiDefinitionStore;

    @Autowired
    private InMemGroupRuleStore inMemGroupRuleStore;

    private final List<String> appList =new ArrayList<>();

    public void init(String app){
        AppInfo appInfo = appManagement.getDetailApp(app);
        //存在说明加载过了，不初始化
        if(appList.contains(app)){
            return;
        }
        appList.add(app);

        try {
            List<RuleEntity> authorityRules = ruleProvider.getRules(appInfo, AuthorityRuleEntity.class);
            inMemAuthorityRuleStore.saveByApp(app,authorityRules.stream().map(ruleEntity -> (AuthorityRuleEntity)ruleEntity).collect(Collectors.toList()));

            List<RuleEntity> degradeRules = ruleProvider.getRules(appInfo, DegradeRuleEntity.class);
            inMemDegradeRuleStore.saveByApp(app,degradeRules.stream().map(ruleEntity -> (DegradeRuleEntity)ruleEntity).collect(Collectors.toList()));

            List<RuleEntity> flowRules = ruleProvider.getRules(appInfo, FlowRuleEntity.class);
            inMemFlowRuleStore.saveByApp(app,flowRules.stream().map(ruleEntity -> (FlowRuleEntity)ruleEntity).collect(Collectors.toList()));

            List<RuleEntity> paramFlowRules = ruleProvider.getRules(appInfo, ParamFlowRuleEntity.class);
            inMemParamFlowRuleStore.saveByApp(app,paramFlowRules.stream().map(ruleEntity -> (ParamFlowRuleEntity)ruleEntity).collect(Collectors.toList()));

            List<RuleEntity> systemRules = ruleProvider.getRules(appInfo, SystemRuleEntity.class);
            inMemSystemRuleStore.saveByApp(app,systemRules.stream().map(ruleEntity -> (SystemRuleEntity)ruleEntity).collect(Collectors.toList()));

            List<RuleEntity> gatewayFlowRules = ruleProvider.getRules(appInfo, GatewayFlowRuleEntity.class);
            inMemGatewayFlowRuleStore.saveByApp(app,gatewayFlowRules.stream().map(ruleEntity -> (GatewayFlowRuleEntity)ruleEntity).collect(Collectors.toList()));

            List<RuleEntity> groupRules = ruleProvider.getRules(appInfo, GroupRuleEntity.class);
            inMemGroupRuleStore.saveByApp(app,groupRules.stream().map(ruleEntity -> (GroupRuleEntity)ruleEntity).collect(Collectors.toList()));

            List<RuleEntity> apiRules = ruleProvider.getRules(appInfo, ApiDefinitionEntity.class);
            inMemApiDefinitionStore.saveByApp(app,apiRules.stream().map(ruleEntity -> (ApiDefinitionEntity)ruleEntity).collect(Collectors.toList()));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void afterSingletonsInstantiated() {
        Set<AppInfo> briefApps = appManagement.getBriefApps();
        briefApps.forEach(briefApp->{
            init(briefApp.getApp());
        });
    }

    public void refresh(String app) {
        appList.remove(app);
    }
}
